package com.zyy.game.tianlong.network;

import com.esotericsoftware.reflectasm.MethodAccess;
import com.zyy.game.tianlong.network.annotation.GameEvent;
import com.zyy.game.tianlong.network.annotation.GameModule;
import com.zyy.game.tianlong.network.annotation.GameResult;
import com.zyy.game.tianlong.network.exception.ApiException;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;

/**
 * springboot启动时运行，映射code与方法
 *
 * @author relufi
 * @date 2019/7/24 0024
 */
@Component
public class GameHandlersAware implements ApplicationContextAware {
    private HandlerMethod[][] handlerMethods;

    /**
     * 在spring bean池内查找code映射方法
     *
     * @param applicationContext spring bea池上下文
     * @throws BeansException 创建Bean失败
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        Map<String, Object> beansWithAnnotation = applicationContext.getBeansWithAnnotation(GameModule.class);
        Map<Integer, Map<Integer, HandlerMethod>> handlerModules = new HashMap<>(16);
        for (Map.Entry<String, Object> stringObjectEntry : beansWithAnnotation.entrySet()) {
            Object o = stringObjectEntry.getValue();
            Class<?> module = o.getClass();
            int opcode = module.getDeclaredAnnotation(GameModule.class).value();
            Method[] declaredMethods = module.getDeclaredMethods();
            Map<Integer, HandlerMethod> handlerMethods = handlerModules.computeIfAbsent(opcode, integer -> new HashMap<>(16));
            MethodAccess methodAccess = MethodAccess.get(module);
            for (Method method : declaredMethods) {
                GameEvent annotation = method.getDeclaredAnnotation(GameEvent.class);
                if (annotation != null) {
                    Class<?>[] parameterTypes = method.getParameterTypes();
                    Integer contextIndex = null;
                    Integer dataIndex = null;
                    Class<?> dataClass = null;
                    for (int i = 0; i < parameterTypes.length; i++) {
                        if (GameContext.class.isAssignableFrom(parameterTypes[i])) {
                            contextIndex = i;
                        } else {
                            dataIndex = i;
                            dataClass = parameterTypes[i];
                        }
                    }
                    int moduleCode = 0;
                    int eventCode = 0;
                    boolean defaultSuccess = false;
                    boolean defaultResult = false;
                    GameResult result = method.getDeclaredAnnotation(GameResult.class);
                    if(result != null) {
                        defaultResult = true;
                        moduleCode = result.eventCode();
                        eventCode = result.moduleCode();
                        defaultSuccess = result.defaultSuccess();
                    }
                    handlerMethods.put(annotation.value(), new HandlerMethod(o, methodAccess, methodAccess.getIndex(method.getName()), contextIndex, method.getParameterCount(), dataIndex, dataClass,moduleCode,eventCode,defaultSuccess,defaultResult));
                }
            }
        }
        // 从HashMap中取出，排序放入数组，以优化速度。
        ArrayList<Map.Entry<Integer, Map<Integer, HandlerMethod>>> entries = new ArrayList<>(handlerModules.entrySet());
        entries.sort(Comparator.comparingInt(Map.Entry::getKey));
        handlerMethods = new HandlerMethod[entries.size()][];
        for (int i = 0; i < entries.size(); i++) {
            ArrayList<Map.Entry<Integer, HandlerMethod>> sortList = new ArrayList<>(entries.get(i).getValue().entrySet());
            sortList.sort(Comparator.comparingInt(Map.Entry::getKey));
            HandlerMethod[] methods = new HandlerMethod[sortList.size()];
            for (int j = 0; j < sortList.size(); j++) {
                methods[j] = sortList.get(j).getValue();
            }
            handlerMethods[i] = methods;
        }
    }

    /**
     * 根据opCode和subCode找到对应的处理器方法
     *
     * @param opCode  模块码
     * @param subCode 事件码
     * @return 处理器方法
     */
    HandlerMethod getHandlerMethod(int opCode, int subCode) {
        try {
            return handlerMethods[opCode][subCode];
        } catch (Exception e) {
            throw new ApiException("opCode=" + opCode + " subCode=" + subCode + " 未找到相应处理器");
        }
    }
}
